/**
* Description: 表格组件
*
* Created by hrx on 2023/9/18
*/
<template>
  <div class="table-component">
    <div class="table-content">
      <el-table ref="tableRef" :data="dataSource" :border="border" style="width: 100%" :row-style="rowStyle"
                @row-click="onRowClick" @sort-change="onSortChange" @select-all="onSelectAll"
                @selection-change="onSelectionChange" :row-key="rowKey" :max-height="maxHeight" :height="maxHeight">

        <template #empty="scope">
          <img style="width: 200px; height: 250px"
               :src="notDataImg"
               alt=""
          />
        </template>
        <el-table-column :key="index" v-for="(item, index) in tableTitles" :label="item.label" :prop="item.prop"
                         :width="item.width" :min-width="item.minWidth" :align="item.align" :type="item.type"
                         :fixed="item.fixed"
                         :sortable="item.sortable" :show-overflow-tooltip="item.showOverflowTooltip"
                         :reserve-selection="item.reserveSelection">
          <template v-if="item.template" #default="scope">
            <slot :name="item.prop" :row="scope.row" :index="scope.$index"></slot>
          </template>
          <template v-else-if="item.type != 'selection'" #default="scope">
            {{ content(scope.row[item.prop]) }}
          </template>
        </el-table-column>
      </el-table>
    </div>
    <div class="pagination" v-if="pagination">
      <el-pagination background @size-change="onPageSizeChange" @current-change="onPageChange"
                     :current-page.sync="ppage" :page-sizes="pageNumberList" :page-size="pnumber"
                     :layout="paginationLayout"
                     :total="dataTotal">
      </el-pagination>
    </div>
  </div>
</template>
<script lang="ts" setup>
import type {IResponseArrayDto, IResponseDto} from '@/utils/request';
import {AxiosResponse} from "axios";
import type {TableInstance} from 'element-plus';
import {ref, onMounted, watch, computed} from 'vue';

export interface Props {
  tableData?: Array<any>,
  tableColumns: Array<ITableColumnItem>,
  rowKey?: string,
  defaultPageNumber?: number,
  border?: boolean,
  pageNumberList?: Array<number>,
  pagination?: boolean,
  autoLoad?: boolean,
  remoteApi?: (params: any) => Promise<any>,
  rowStyle?: (rowData: any) => any,
  ppageFieldName?: string,
  pnumberFieldName?: string,
  fixedHeaderMaxHeight?: number,
  sortPropFieldName?: string,
  sortDirectionFieldName?: string,
  emptyContent?: string,
  paginationLayout?: string;
  notDataImg?: string;
}

export interface ITableColumnItem {
  label: string,
  prop: string,
  type?: "selection" | "index" | "expand",
  width?: string,
  minWidth?: string,
  align?: string,
  fixed?: boolean | 'right' | 'left',
  sortable?: boolean | 'custom',
  showOverflowTooltip?: boolean,
  reserveSelection?: boolean,
  template?: boolean;
}


const props = withDefaults(defineProps<Props>(), {
  tableData: () => [],
  tableColumns: () => [],
  defaultPageNumber: 10,
  border: false,
  pageNumberList: () => [10, 50, 100],
  pagination: true,
  autoLoad: false,
  ppageFieldName: 'ppage',
  pnumberFieldName: 'pnumber',
  sortPropFieldName: 'pcolumn',
  sortDirectionFieldName: 'pdirection',
  rowStyle: () => {
    return {height: "60px"}
  },
  emptyContent: '',
  paginationLayout: "total, sizes, prev, pager, next, jumper",
  fixedHeaderMaxHeight: 800,
  notDataImg:"https://iotest.dictech.com.cn/image/wechat/train/notData.png",
});


let sortProp: string | undefined = undefined;
let sortDirection: boolean | undefined = undefined;
let queryParams: any;
const tableRef = ref<TableInstance>();
const tableTitles = ref<Array<ITableColumnItem>>(props.tableColumns);
const dataSource = ref<Array<any>>([]);
const dataTotal = ref(0);
const ppage = ref(1);
const pnumber = ref(props.defaultPageNumber);

const emit = defineEmits(['on-click-row', 'on-loaded', 'on-data-change', 'on-select-all', 'on-selection-change', 'sort-change']);

watch(() => props.tableData, (newVal) => {
  let data: Array<any> = !props.remoteApi && newVal ? [...newVal] : [];
  let currentPageData: Array<any> = newVal;
  if (props.pagination && newVal.length > 0) {
    currentPageData = newVal.slice((ppage.value - 1) * pnumber.value, ppage.value * pnumber.value);
  }
  dataSource.value = currentPageData;
  dataTotal.value = data.length;
}, {deep: true, immediate: true});

watch(() => props.tableColumns, (newVal) => {
  tableTitles.value = newVal;
}, {deep: true});

watch(() => dataSource, (newVal) => {
  emit('on-data-change', newVal);
}, {deep: true});

const content = computed(() => (value: any) => {
  return value !== null || value !== undefined ? value : props.emptyContent;
});

const maxHeight = computed(() => {
  let res;
  if (props.fixedHeaderMaxHeight) {
    res = props.fixedHeaderMaxHeight;
    if (props.pagination) {
      res -= 150;
    }
  }
  return res;
});

onMounted(() => {
  props.autoLoad && queryData();
});

const queryData = (queryParams?: any) => {
  getDataSourceFormServer(queryParams);
};

const refreshData = (queryParams?: any) => {
  ppage.value = 1;
  pnumber.value = props.defaultPageNumber;
  getDataSourceFormServer(queryParams);
};


const getDataSourceFormServer = async (params?: any) => {
  if (!props.remoteApi) {
    return;
  }
  queryParams = params;
  const p: any = {
    [props.ppageFieldName]: props.pagination ? ppage.value : undefined,
    [props.pnumberFieldName]: props.pagination ? pnumber.value : undefined,
    [props.sortPropFieldName]: sortProp,
    [props.sortDirectionFieldName]: sortDirection,
    ...params
  };
  const res: AxiosResponse<IResponseDto<IResponseArrayDto<any>>> = await props.remoteApi(p);
  const {list, totalCount} = res.data.data;
  dataSource.value = list;
  dataTotal.value = totalCount;
  props.autoLoad && emit('on-loaded', res.data);
  await nextTick(() => {
    tableRef?.value?.setScrollTop(0)
  })
};

const onPageChange = (page: number) => {
  ppage.value = page;
  if (props.remoteApi) {
    getDataSourceFormServer(queryParams);
  } else {
    dataSource.value = props.tableData ? props.tableData.slice((page - 1) * pnumber.value, page * pnumber.value) : [];
  }
};

const onPageSizeChange = (size: number) => {
  ppage.value = 1;
  pnumber.value = size;
  if (props.remoteApi) {
    getDataSourceFormServer(queryParams);
  } else {
    dataSource.value = props.tableData ? props.tableData.slice(0, size) : [];
  }
};

const onRowClick = (row: any) => {
  emit('on-click-row', row);
};

const onSelectAll = (selection: Array<any>) => {
  emit('on-select-all', selection);
};

const onSelectionChange = (selection: Array<any>) => {
  emit('on-selection-change', selection);
};

const onSortChange = (column: any) => {
  // const {prop, order} = column;
  // sortProp = order === null ? undefined : prop;
  // sortDirection = order === null ? undefined : order === 'ascending';
  // getDataSourceFormServer(queryParams);
  emit('sort-change', column)
};

const clearSelection = () => {
  tableRef?.value?.clearSelection();
};

const refreshSelection = (selection: Array<any> = []) => {
  clearSelection();
  selection.forEach(row => {
    if (row) {
      toggleRowSelection(row, true);
    }
  });
};

const toggleRowSelection = (row: any, val: boolean) => {
  tableRef?.value?.toggleRowSelection(row, val);
};

const getDataSource = (): Array<any> => {
  return dataSource.value;
};

const getTotal = (): number => {
  return dataTotal.value;
};

const getPageNumber = (): number => {
  return ppage.value;
};

const getPageSize = (): number => {
  return pnumber.value;
};

defineExpose({
  queryData,
  refreshData,
  getPageSize,
  getPageNumber,
  getTotal,
  getDataSource,
  toggleRowSelection,
  refreshSelection,
  clearSelection,
})

</script>

<style lang="scss" scoped>
.table-component {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  .el-table__header {
    width: 100% !important;
  }
  .el-table__body  {
    width: 100% !important;
  }
  .table-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: auto;
  }

  .pagination {
    display: flex;
    justify-content: flex-end;
    float: right;
    padding: 10px 20px 9px 20px;
    align-items: center;
    color: #252631;
  }
}
</style>